package site.sorghum.ddl;

import site.sorghum.ddl.dialect.MySQLDDLDialect;
import site.sorghum.ddl.dialect.OracleDDLDialect;
import site.sorghum.ddl.dialect.PostgreSQLDDLDialect;
import site.sorghum.ddl.dialect.SQLServerDDLDialect;
import site.sorghum.ddl.enums.DbType;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

/**
 * DDL方言工厂
 */
public class DDLDialectFactory {

    private static final Map<DbType, DDLDialect> DIALECT_MAP = new HashMap<>();

    static {
        registerDialect(new MySQLDDLDialect());
        registerDialect(new OracleDDLDialect());
        registerDialect(new SQLServerDDLDialect());
        registerDialect(new PostgreSQLDDLDialect());
    }

    public static void registerDialect(DDLDialect dialect) {
        DIALECT_MAP.put(dialect.getDatabaseType(), dialect);
    }

    /**
     * 根据连接字符串猜测数据库类型
     * @param connectionString 数据库连接字符串
     * @return 猜测的数据库类型
     * @throws IllegalArgumentException 如果无法猜测数据库类型
     */
    public static DDLDialect guess(String connectionString) {
        if (connectionString == null || connectionString.isEmpty()) {
            throw new IllegalArgumentException("Connection string cannot be null or empty");
        }

        if (connectionString.toLowerCase().contains("jdbc:mysql:")) {
            return getDialect(DbType.MYSQL);
        } else if (connectionString.toLowerCase().contains("jdbc:oracle:")) {
            return getDialect(DbType.ORACLE);
        } else if (connectionString.toLowerCase().contains("jdbc:sqlserver:")) {
            return getDialect(DbType.SQLSERVER);
        } else if (connectionString.toLowerCase().contains("jdbc:postgresql:")) {
            return getDialect(DbType.POSTGRESQL);
        } else {
            throw new IllegalArgumentException("Unable to guess database type from connection string: " + connectionString);
        }
    }

    /**
     * 根据数据源猜测数据库类型
     * @param dataSource 数据源
     * @return 数据库类型
     */
    public static DDLDialect guess(DataSource dataSource){
        if (dataSource == null) {
            throw new IllegalArgumentException("DataSource cannot be null");
        }

        String connectionString = null;
        try (Connection connection = dataSource.getConnection()) {
            connectionString = connection.getMetaData().getURL();
            return guess(connectionString);
        } catch (SQLException e) {
            throw new IllegalArgumentException("Failed to get connection from DataSource", e);
        }
    }

    public static DDLDialect getDialect(DbType databaseType) {
        DDLDialect dialect = DIALECT_MAP.get(databaseType);
        if (dialect == null) {
            throw new IllegalArgumentException("Unsupported database type: " + databaseType);
        }
        return dialect;
    }
}